#pragma once
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Log.hpp"
#include "Thread.hpp"
#include <iostream>
#include <unistd.h>
#include <memory>
#include <vector>
#include <queue>
#include <functional>

namespace MyThreadPool
{
    using namespace MyCond;
    using namespace MyPhread_Modle;
    using namespace MpthreayMutex;
    using namespace LogModule;

    using thread_t = std::shared_ptr<Thread>;

    int defaultnum = 5;

    template <class T>
    class threadpool
    {
    private:
        void defaultfun()
        {
            while (true)
            {
                LOG(LogLevel::INFO) << "这是一个测试函数";
                sleep(1);
            }
        }
        bool IsEmpty() { return _taskq.empty(); }
        
        void HandlerTask()
        {
            // 1. 拿任务
            while (true)
            {
                T t;
                {
                    LockGround lock(_mtx);
                    // 如果没有任务的话只能去阻塞住
                    // LOG(LogLevel::INFO) << "线程： " << name << ", 进入HandlerTask"; 
                    while (IsEmpty() && _isruning)
                    {
                        _wait_num++;
                        _cond.wait(_mtx);
                        _wait_num--;
                    }
                    if (IsEmpty() && !_isruning) break;
                    t = _taskq.front();
                    _taskq.pop();
                }
                // 2. 处理任务
                t();
            }
        }

        threadpool(int num = defaultnum) : _num(num) , _wait_num(0),_isruning(false)
        {
            for (int i = 0; i < num; i++)
            {
                // threads.push_back(std::make_shared<Thread>(std::bind(&threadpool::defaultfun,this)));
                threads.push_back(std::make_shared<Thread>([this,i]
                                                           { HandlerTask(); }));
            }
        }
        threadpool(const threadpool<T>& tt) = default;
        threadpool<T>& operator=(const threadpool<T>& tt) = default;
    public:

        void stop()
        {
            if (!_isruning) return;

            {
                // LOG(LogLevel::INFO) << "停止要开始了，要开始唤醒所有等待的进程了////////////////////////////////////////////////";
                LockGround lock(_mtx);
                if (_wait_num > 0)
                {
                    _cond.NotifyAll();
                }
            }
            // LOG(LogLevel::INFO) << "开始停止了////////////////////////////////////////////////";
            // sleep(3);
            for (auto thread_ptr:threads) 
            {
                // LOG(LogLevel::INFO) << "停止线程前 -> 现在还剩下: " << _taskq.size() << "个任务";
                thread_ptr->Stop(); //如果线程还在执行某种任务呢?
                LOG(LogLevel::INFO) << "停止线程: " << thread_ptr->Name() << "成功";
                // LOG(LogLevel::INFO) << "停止线程后 -> 现在还剩下: " << _taskq.size() << "个任务";
            }
            _isruning = false;
        }

        void Equeue(T& data)
        {
            if (!_isruning) return;
            LockGround lock(_mtx);
            _taskq.push(data);
            if (_wait_num > 0) _cond.Notify();
        }
        void Launch() // 启动进程
        {
            if (_isruning) return; //如果已经被启动了，那么直接返回
            _isruning = true;
            for (auto thread_ptr : threads)
            {
                LOG(LogLevel::INFO) << "启动线程: " << thread_ptr->Name() << " 成功";
                thread_ptr->Start();
            }
        }

        void Wait() // 等待进程
        {
            for (auto thread_ptr : threads)
            {
                LOG(LogLevel::INFO) << "回收线程: " << thread_ptr->Name() << " 成功";
                thread_ptr->Join();
            }
        }

        ~threadpool()
        {
        }
        //懒汉模式
        static threadpool<T>* _myinstance;
        static Mutex mutx;
        static threadpool<T>* Getinstance()
        {
            //如果有多个线程初始化单例呢? 加锁保护 
            if (threadpool<T>::_myinstance == nullptr)
            {
                LockGround lock(mutx);
                if (threadpool<T>::_myinstance == nullptr)
                {
                    std::cout << "我要开始初始化了" << std::endl;
                    threadpool<T>::_myinstance = new threadpool();
                    threadpool<T>::_myinstance->Launch();
                }
            }
            return threadpool<T>::_myinstance;
        }
    private:
        int _num;
        std::vector<thread_t> threads;
        std::queue<T> _taskq; // 任务队列
        Mutex _mtx;
        Cond _cond;
        int _wait_num;
        bool _isruning;
    };
    template<class T>
    threadpool<T>* threadpool<T>::_myinstance = nullptr;
    template<class T>
    Mutex threadpool<T>::mutx;
}
